package cmd

import (
	"fmt"
	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/memstore"
	"github.com/gin-gonic/gin"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"net/http"
	"strconv"
	"web1/util"
)

type homedata struct {
	Id           int
	Rentnumber   int
	Returnnumber int
	Processednum int
	Untreatednum int
	Daytime      string
}

type goods struct {
	Id             int
	Name           string
	Inputdata      string
	Numberofleases int
	Inventory      int
	Currinvent     int
}

type leaserequests struct {
	Orderid       int
	Id            int
	Userid        int
	Create_time   string
	Currten_time  string
	Currinvent    int
	Isacceptornot string
}

type leaserecords struct {
	Cordid       int
	Id           int
	Create_time  string
	Currten_time string
	Currinvent   int
	Isreturned   string
}

type users struct {
	Userid   int
	Name     string
	Password string
}

type adms struct {
	Id       int
	Username string
	Number   string
	Passord  string
}

type requests struct {
	Orderid       int
	Id            int
	Userid        int
	Create_time   string
	Currten_time  string
	Currinvent    int
	Isacceptornot string
	Name          string
}

var (
	DB *gorm.DB
)

func InitDB() (*gorm.DB, error) {
	dsn := "root:123456@tcp(127.0.0.1:3306)/bubble?charset=utf8mb4&parseTime=True&loc=Local"
	var err error
	DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		return nil, err
	}
	return DB, nil
}

func GetDB() *gorm.DB {
	return DB
}

func Getmax(DB *gorm.DB, name string, tabname string) (int, error) {
	var id int
	var err error
	if err1 := DB.Raw("SELECT MAX(" + name + ") FROM " + tabname).Scan(&id).Error; err != nil {
		err = err1
	}
	return id, err
}
func sql(DB *gorm.DB) (homedata, error) {
	var ans homedata
	//var ans homedata
	err := DB.Where("daytime", util.GetDay()).Find(&ans).Error
	return ans, err
}

func Execute() {
	r := gin.Default()
	store := memstore.NewStore([]byte("secret"))
	r.Use(sessions.Sessions("mysession", store))
	r.Use(util.Core())
	r.LoadHTMLGlob("templates/*")
	r.GET("/index", func(context *gin.Context) {
		context.HTML(http.StatusOK, "index.html", nil)
	})
	_, err := InitDB()
	if err != nil {
		panic(err)
		return
	}
	DB := GetDB()
	//路由组
	vGroup := r.Group("/managentstore")
	//vGrou
	{
		//模糊查询 搜索书本
		vGroup.Any("/serachgoods", func(context *gin.Context) {
			name := context.PostForm("name")
			//fmt.Println(name)
			var goos []goods
			if err := DB.Where(fmt.Sprintf(" name like %q ", ("%" + name + "%"))).Find(&goos).Error; err != nil {
				context.JSON(http.StatusOK, gin.H{
					"err": err.Error(),
				})
			}
			context.JSON(http.StatusOK, gin.H{
				"title": goos,
			})
		})

		//刷新数据库资源（让书本借出量、余量统一）
		vGroup.PUT("/flush", func(context *gin.Context) {
			//MySQL触发器已经让goods书本余量会自减，因此以goods货物为基准
			var goodlist []goods

			if err := DB.Find(&goodlist).Error; err != nil {
				context.JSON(http.StatusOK, gin.H{"err": err})
				return
			}
			//批量刷新
			for i := 0; i < len(goodlist); i++ {
				if err_ := DB.Exec("update leaserequests set currinvent=? where id = ?", goodlist[i].Currinvent, goodlist[i].Id).Error; err_ != nil {
					context.JSON(http.StatusOK, gin.H{"error": err_})
					return
				}
				if err_1 := DB.Exec("update leaserecords set currinvent=? where id = ?", goodlist[i].Currinvent, goodlist[i].Id).Error; err_1 != nil {
					context.JSON(http.StatusOK, gin.H{"error": err_1})
					return
				}

			}
			context.JSON(http.StatusOK, gin.H{"title": "OK"})
		})
		//登录请求
		vGroup.POST("/login", func(context *gin.Context) {
			id := context.PostForm("id")
			pass := context.PostForm("password")
			//验证用户身份，管理员or用户
			userid, err0 := strconv.Atoi(id)
			if err0 != nil {
				context.JSON(http.StatusOK, gin.H{
					"err": err0.Error(),
				})
				return
			}
			var incode string
			var pass_user_un string
			var name string
			if userid > 2300 {
				incode = "1"
				var ad adms
				if err := DB.Where("id=?", id).First(&ad).Error; err != nil {
					context.JSON(http.StatusOK, gin.H{
						"err": "身份错误，请联系管理员或者检查身份",
					})
					return
				}
				pass_user := ad.Passord
				name = ad.Username
				pass_user_un = util.AesDecrypt(pass_user, util.Getkey())
				if pass_user_un != pass {
					context.JSON(http.StatusOK, gin.H{"err": "用户名或密码错误!"})
					return
				}
			} else {
				incode = "0"
				var use users
				if err := DB.Where("userid=?", id).First(&use).Error; err != nil {
					context.JSON(http.StatusOK, gin.H{
						"err": "身份错误，请联系管理员或者检查身份",
					})
					return
				}
				if use.Userid != userid {
					context.JSON(http.StatusOK, gin.H{"err": "身份错误，请联系管理员或者检查身份"})
					return
				}
				pass_user := use.Password
				name = use.Name
				pass_user_un = util.AesDecrypt(pass_user, util.Getkey())
				if pass_user_un != pass {
					context.JSON(http.StatusOK, gin.H{"err": "用户名或密码错误!"})
					return
				}
			}

			scert := util.Getscret()
			token, err1 := util.GenerateToken(scert, pass, name, incode, 4600)
			if err1 != nil {
				context.AbortWithError(http.StatusOK, err1)
				return
			}
			var menu []gin.H
			if incode == "1" {
				menu = append(menu, gin.H{
					"title": "首页",
					"path":  util.GroupText(util.Home),
				})
				menu = append(menu, gin.H{
					"title": "货物",
					"path":  util.GroupText(util.Goods),
				})
				menu = append(menu, gin.H{
					"title": "租借请求",
					"path":  util.GroupText(util.GoodsRent),
				})
				menu = append(menu, gin.H{
					"title": "租借记录",
					"path":  util.GroupText(util.RentNote),
				})
				menu = append(menu, gin.H{
					"title": "个人中心",
					"path":  util.GroupText(util.Personal),
				})
			} else {
				menu = append(menu, gin.H{
					"title": "首页",
					"path":  util.GroupText(util.Home),
				})
				menu = append(menu, gin.H{
					"title": "货物",
					"path":  util.GroupText(util.Goods),
				})
				menu = append(menu, gin.H{
					"title": "租借请求",
					"path":  util.GroupText(util.RentRequests),
				})
				menu = append(menu, gin.H{
					"title": "个人中心",
					"path":  util.GroupText(util.Personal),
				})
			}
			session := sessions.Default(context)
			session.Set("token", token)
			session.Save()
			context.JSON(http.StatusOK, gin.H{
				"token":    token,
				"idcode":   incode,
				"userMenu": menu,
			})
		})

		//首页
		vGroup.GET("/home", util.Hom(), func(context *gin.Context) {
			//context.Redirect()//暂定重定向
			session := sessions.Default(context)
			token := session.Get("token")
			s := fmt.Sprintf("%v", token)
			//fmt.Println(s)
			clims, err := util.ParseToken(util.Getscret(), s)
			if err != nil {
				context.JSON(http.StatusOK, gin.H{
					"err": err.Error(),
				})
				return
			}
			incode := clims["incode"]
			if incode == "1" {
				ans, err0 := sql(DB)
				if err0 != nil {
					context.JSON(http.StatusOK, gin.H{
						"err0": err0.Error(),
					})
					return
				}
				context.JSON(http.StatusOK, gin.H{
					"rentNumber":   ans.Rentnumber,
					"Processednum": ans.Processednum,
					"returnNumber": ans.Returnnumber,
					"Untreatednum": ans.Untreatednum,
				})
			}
		})
		//货物
		vGroup.GET("/goods", func(context *gin.Context) {
			var goodsList []goods
			if err = DB.Find(&goodsList).Error; err != nil {
				context.JSON(http.StatusOK, gin.H{"error": err.Error()})
				return
			} else {
				context.JSON(http.StatusOK, goodsList)
			}
		})
		//用户租借请求
		vGroup.POST("/goodsrent", func(context *gin.Context) {
			book_id := context.PostForm("goodsid")
			rentdata := context.PostForm("Rentdata")
			usersid := context.PostForm("userid")
			formatTimeStr := util.Getunix()
			int1, err2 := strconv.Atoi(rentdata)
			int2, err3 := strconv.Atoi(book_id)
			int3, err4 := strconv.Atoi(usersid)
			if err2 != nil || err3 != nil || err4 != nil {
				context.JSON(http.StatusOK, gin.H{"askDData": gin.H{
					"prompt": "errs",
					"defeatReason": gin.H{
						"err1": err2,
						"err2": err3,
						"err3": err4,
					},
				}})
				return
			}
			orderid_, err6 := util.Getmax(DB, "orderid", "leaserequests")
			orderid_++
			if err6 != nil {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":       "error",
						"defeatReason": err6,
					},
				})
			}
			re := util.Daytime(int1)
			req :=
				leaserequests{
					orderid_,
					int2,
					int3,
					formatTimeStr,
					re,
					100,
					"0",
				}
			if err = DB.Create(&req).Error; err != nil {
				context.JSON(http.StatusOK, gin.H{"askDData": gin.H{
					"prompt":       "errs",
					"defeatReason": err,
				}})
				return
			} else {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":       "OK",
						"defeatReason": nil,
					},
				})
			}
		})
		//管理员新增请求
		vGroup.Any("/goods/add", func(context *gin.Context) {
			name := context.PostForm("name")
			id, err0 := util.Getmax(DB, "id", "goods")
			if err0 != nil {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":        "err",
						"ddefeatReason": err0.Error(),
					},
				})
				return
			}
			cretime := util.Getunix()
			book_id := id
			book_id++
			currtnum := context.PostForm("addNum")
			fmt.Println(name, currtnum)
			cur1, err4 := strconv.Atoi(currtnum)
			if err4 != nil {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":       "err",
						"defeatReason": err4.Error(),
					},
				})
				return
			}
			books := goods{
				book_id,
				name,
				cretime,
				0,
				cur1,
				cur1,
			}
			if err = DB.Create(&books).Error; err != nil {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":        "err",
						"ddefeatReason": err.Error(),
					},
				})
				return
			} else {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":       "OK",
						"defeatReason": nil,
					},
				})
			}
		})
		//管理员删除请求
		vGroup.DELETE("/goods/delete/:goodsid", func(context *gin.Context) {
			id, ok := context.Params.Get("goodsid")
			if !ok {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":       "ERROR",
						"defeatReason": "无效的图书ID",
					},
				})
				return
			}

			if err = DB.Exec("DELETE FROM goods WHERE id=" + id).Error; err != nil {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":       "ERROR",
						"defeatReason": err,
					},
				})
				return
			} else {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":       "OK",
						"defeatReason": nil,
					},
				})
			}
		})
		//租借记录
		vGroup.GET("/rentNote", func(context *gin.Context) {
			var noteList []leaserecords
			if err = DB.Find(&noteList).Error; err != nil {
				context.JSON(http.StatusOK, gin.H{"error": err.Error()})
				return
			} else {
				context.JSON(http.StatusOK, noteList)
			}
		})
		//管理员删除租借记录
		vGroup.DELETE("/rentNote/delete/:rentid", func(context *gin.Context) {
			orderid, ok := context.Params.Get("rentid")
			if !ok {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":       "ERROR",
						"defeatReason": "无效的订单ID",
					},
				})
				return
			}
			if err = DB.Exec("delete from leaserecords where cordid=?", orderid).Error; err != nil {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":       "ERROR",
						"defeatReason": err,
					},
				})
				return
			} else {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":       "Deleted",
						"defeatReason": nil,
					},
				})
			}
		})
		//租借请求
		vGroup.GET("/rentRequests", func(context *gin.Context) {
			//解析token获取用户名
			session := sessions.Default(context)
			tokens := session.Get("token")
			token := fmt.Sprintf("%v", tokens)
			clims, err := util.ParseToken(util.Getscret(), token)
			if err != nil {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":       "ERROR1",
						"defeatReason": err.Error(),
					},
				})
				return
			}
			name := clims["name"]
			incode := clims["incode"]
			var rentReuestlist []leaserequests
			if incode == "0" {
				err_ := DB.Where("userid in (select userid from users where name=?)", name).Find(&rentReuestlist).Error
				if err_ != nil {
					context.JSON(http.StatusOK, gin.H{
						"err2": err_,
					})
					return
				}
				context.JSON(http.StatusOK, rentReuestlist)
			} else {
				context.JSON(http.StatusNotFound, gin.H{
					"title": "错误的身份码",
				})
			}
		})
		//管理员
		vGroup.GET("/adminRent", func(context *gin.Context) {
			session := sessions.Default(context)
			tokens := session.Get("token")
			token := fmt.Sprintf("%v", tokens)
			clims, err := util.ParseToken(util.Getscret(), token)
			if err != nil {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":       "ERROR1",
						"defeatReason": err.Error(),
					},
				})
				return
			}
			incode := clims["incode"]
			if incode != "1" {
				context.JSON(http.StatusOK, gin.H{
					"msg": "error",
				})
			}
			var rentrequeslist1 []requests
			if err_1 := DB.Model(&leaserequests{}).Select("leaserequests.orderid,leaserequests.id,leaserequests.userid,leaserequests.create_time,leaserequests.currten_time,leaserequests.currinvent,leaserequests.isacceptornot,goods.name").Joins("left join goods on leaserequests.id = goods.id").Scan(&rentrequeslist1).Error; err_1 != nil {
				context.JSON(http.StatusOK, gin.H{
					"err3": err_1,
				})
				return
			}
			context.JSON(http.StatusOK, rentrequeslist1)
		})

		//归还请求
		vGroup.POST("/rentRequests/returned", func(context *gin.Context) {
			//设置触发器：1，在更新记录表时（也就是当还书后），库存自动加一。库存加一的表如下：goods表，请求表，记录表
			//          2，无需设置事件，MySQL每隔十秒扫描一遍包，使当前已借出严格等于总量减库存，使用刷新即可
			orderid := context.PostForm("rentReqId")
			if err := DB.Exec("UPDATE leaserecords SET isreturned=? where cordid=?", "1", orderid).Error; err != nil {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"prompt":       "归还失败",
						"defeatRenson": err,
					},
				})
			}
			//TODO 定位到这里
			var goods_up leaserecords
			if err := DB.Where("cordid=?", orderid).Find(&goods_up).Error; err != nil {
				context.JSON(http.StatusOK, gin.H{
					"title": err,
				})
				return
			}
			if err_ := DB.Exec("UPDATE goods SET currinvent=currinvent+1 WHERE id = ?", goods_up.Id).Error; err_ != nil {
				context.JSON(http.StatusOK, gin.H{
					"title": err_,
				})
				return
			}
			//UPDATE homedata set returnnumber=returnnumber+1 WHERE daytime = curdate()
			if err_ := DB.Exec("UPDATE homedata set returnnumber=returnnumber+1 WHERE daytime = curdate()").Error; err_ != nil {
				context.JSON(http.StatusOK, gin.H{
					"title": err_,
				})
				return
			}
			if err_ := DB.Exec("UPDATE homedata SET rentnumber=rentnumber-1 WHERE daytime = curdate()").Error; err_ != nil {
				context.JSON(http.StatusOK, gin.H{
					"title": err_,
				})
				return
			}
			context.JSON(http.StatusOK, gin.H{
				"askData": gin.H{
					"prompt":       "归还成功",
					"defeatRenson": nil,
				},
			})

		})
		//用户撤销请求
		vGroup.POST("/rentRequests/cancel/:rentreqid", func(context *gin.Context) {
			rentReqid, ok := context.Params.Get("rentreqid")
			if !ok {
				context.JSON(http.StatusOK, gin.H{"error": "无效的id"})
				return
			}
			var ends leaserequests
			if err1 := DB.Where("orderid=?", rentReqid).First(&ends).Error; err1 != nil {
				context.JSON(http.StatusOK, gin.H{"askData": gin.H{"prompt": "err", "defeatReason": err1.Error()}})
				return
			}
			if ends.Isacceptornot == "0" {
				context.JSON(http.StatusOK, gin.H{"askData": gin.H{"prompt": "err", "defeatReason": "管理员已同意，不能撤销"}})
				return
			}
			if err := DB.Exec("DELETE FROM leaserequests WHERE orderid=?", rentReqid).Error; err != nil {
				context.JSON(http.StatusOK, gin.H{"askData": gin.H{"prompt": "err", "defeatReason": err.Error()}})
				return
			}
			context.JSON(http.StatusOK, gin.H{
				"askData": gin.H{
					"prompt": "OK",
				},
			})
		})
		//管理员是否同意租借请求
		vGroup.POST("/rentRequest/agree", func(context *gin.Context) {
			//参数：isagree（布尔值0，1）rentReqsId：唯一标识（数值型） 返回：
			//获取参数
			isagree := context.PostForm("isAgree")
			req := context.PostForm("rentReqId")
			if isagree != "1" {
				context.JSON(http.StatusOK, gin.H{
					"askData": gin.H{
						"title": "未同意",
					},
				})
				return
			}
			//获取未受理的记录
			var temp leaserequests
			if err := DB.Where("orderid=?", req).First(&temp).Error; err != nil {
				context.AbortWithError(http.StatusOK, err)
				return
			}
			cur1, err4 := strconv.Atoi(req)
			if err4 != nil {
				context.JSON(http.StatusOK, gin.H{
					"agreeData": gin.H{
						"prompt":       "err",
						"defeatReason": err4.Error(),
					},
				})
				return
			}
			temp.Orderid = cur1
			temp.Isacceptornot = isagree
			if err := DB.Exec("update `leaserequests` set `isacceptornot`=? where orderid=?", isagree, req).Error; err != nil {
				context.AbortWithError(http.StatusOK, err)
				return
			}
			////模拟触发器，当是否受理为已受理时，触发器自动把记录插入记录表中，并且默认未还书，不能使用MySQL触发器，无法获取值
			ans := leaserecords{
				temp.Orderid,
				temp.Id,
				temp.Create_time,
				temp.Currten_time,
				temp.Currinvent,
				"0",
			}
			if err := DB.Create(&ans).Error; err != nil {
				context.AbortWithError(http.StatusOK, err)
				return
			}
			context.JSON(http.StatusOK, gin.H{
				"agreeData": gin.H{
					"title": 1,
				},
			})
		})
		//个人中心
		vGroup.GET("/personal", func(context *gin.Context) {
			//参数:用户登录token	返回：用户名
			session := sessions.Default(context)
			tokens := session.Get("token")
			token := fmt.Sprintf("%v", tokens)
			clims, err := util.ParseToken(util.Getscret(), token)
			if err != nil {
				context.JSON(http.StatusOK, gin.H{"err": err.Error()})
				return
			}
			name := clims["name"]
			context.JSON(http.StatusOK, gin.H{
				"userData": gin.H{
					"username": name,
				},
			})
		})
		//修改密码
		vGroup.POST("/revise", func(context *gin.Context) {
			//参数 token 新密码
			session := sessions.Default(context)
			tokens := session.Get("token")
			token := fmt.Sprintf("%v", tokens)
			//fmt.Println(token)
			clims, err := util.ParseToken(util.Getscret(), token)
			if err != nil {
				context.JSON(http.StatusOK, gin.H{
					"err": err.Error(),
				})
				return
			}
			name := clims["name"]
			incode := clims["incode"]
			pass := context.PostForm("pass")
			pass_ := util.AesEncrypt(pass, util.Getkey())
			if incode == "1" {
				if err2 := DB.Exec("UPDATE adms SET passord=? where username=?", pass_, name).Error; err != nil {
					context.JSON(http.StatusOK, gin.H{
						"err": err2.Error(),
					})
					return
				}
				context.JSON(http.StatusOK, gin.H{
					"title": "OK",
				})
			} else {
				if err2 := DB.Exec("UPDATE users SET password=? where name=?", pass_, name).Error; err != nil {
					context.JSON(http.StatusOK, gin.H{
						"err": err2.Error(),
					})
					return
				}
				context.JSON(http.StatusOK, gin.H{
					"title": "OK",
				})
			}
		})
		//每天记录日志
		vGroup.POST("/log", func(context *gin.Context) {
			max, err := util.Getmax(DB, "id", "homedata")
			max++
			if err != nil {
				context.JSON(http.StatusOK, gin.H{
					"err": err.Error(),
				})
				return
			}
			var homed homedata

			homed.Id = max
			homed.Daytime = util.GetDay()
			DB.AutoMigrate(&homed)
			if err1 := DB.Create(&homed).Error; err != nil {
				context.JSON(http.StatusOK, gin.H{
					"err": err1.Error(),
				})
				return
			}
			context.JSON(http.StatusOK, gin.H{
				"title": "ok",
			})
		})
	}
	r.Run(":9090")
}
